﻿/*
 * Twipler - Twitter Web Client with features.
 *  
 *  Copyright (C) 2010. Ian Quigley
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details. 
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Twipler.App.Parse;
using Twipler.Xtensions;

namespace Twipler.App.Render.Effect
{
    public enum TweetSectionType { NormalText, Url, AtName, HashCode }

    public class TweetSection
    {
        public TweetSectionType SectionType { get; internal set; }
        public virtual string Text { get; internal set; }

        public TweetSection()
        {
        }

        public TweetSection(TweetSectionType type, string text)
        {
            SectionType = type;
            Text = text;
        }
    }


    public class TweetDecoder
    {
        public static List<TweetSection> Decode(string tweet)
        {
            List<KeyValuePair<int, TweetSectionType>> stateChanges = new List<KeyValuePair<int, TweetSectionType>>();
            StringParser parse = new StringParser(tweet);

            int index;
            int previousIndex = 0;

            while (!parse.IsEmpty)
            {
                string found = parse.FindNext(true, out index, "@", "http", "www.", "#");
                if (found == null)
                {
                    stateChanges.Add(new KeyValuePair<int, TweetSectionType>(tweet.Length, TweetSectionType.NormalText));
                    break;
                }

                if (index != previousIndex)
                {
                    stateChanges.Add(new KeyValuePair<int, TweetSectionType>(previousIndex, TweetSectionType.NormalText));
                    parse.ConsumeUpTo(index);
                }

                if ((found == "@") || (found == "#"))
                {
                    if ((parse.Index != 0) && (parse.PrevChar.IsIn(" ,.([{")))
                    {
                        parse.SkipChar();
                        continue;
                    }

                    parse.SkipChar();

                    if (!parse.IsEmpty)
                    {

                        if (parse.NextChar.Is_azAZ09() || parse.NextChar == '_')
                            stateChanges.Add(new KeyValuePair<int, TweetSectionType>(parse.Index - 1, found == "@" ? TweetSectionType.AtName : TweetSectionType.HashCode));

                        parse.ReadWhile(c => c.Is_azAZ09() || c == '_');
                    }
                }

                if ((found == "http") || (found == "www."))
                {
                    if ((parse.Index != 0) && (parse.PrevChar != ' '))
                    {
                        parse.SkipChar();
                        continue;
                    }

                    parse.SkipOver(found);

                    if ((!parse.IsEmpty) && (parse.NextChar == 's' || parse.NextChar == 'S'))
                    {
                        found += parse.NextChar;
                        parse.SkipChar();
                    }

                    if (!parse.IsEmpty && (parse.NextChar == ':' || (found == "www." && parse.NextChar.Is_UrlValid())))
                    {
                        found += parse.ReadWhile(c => c.Is_UrlValid());

                        // smallest string possible: www.a.cc   (http:/a.cc is 10 chars)
                        if (found.Length >= 8)
                            stateChanges.Add(new KeyValuePair<int, TweetSectionType>(parse.Index - found.Length, TweetSectionType.Url));
                    }
                }

                previousIndex = parse.Index;
            }

            List<TweetSection> sections = new List<TweetSection>();

            if (stateChanges.Count() == 0)
            {
                sections.Add(new TweetSection(TweetSectionType.NormalText, tweet));
            }
            else
            {

                index = 0;
                int from = 0;
                for (int i = 0; i < stateChanges.Count() - 1; i++)
                {
                    if ((stateChanges[i + 1].Value == TweetSectionType.NormalText) && (stateChanges[i].Value == TweetSectionType.NormalText))
                        continue;

                    index = stateChanges[i + 1].Key;
                    sections.Add(new TweetSection(stateChanges[i].Value, tweet.Substring(from, index - from)));
                    from = index;
                }

                sections.Add(new TweetSection(stateChanges[stateChanges.Count() - 1].Value, tweet.Substring(index)));
            }
            return sections;
        }
    }
}
